#pragma once
#include <iostream>
#include <string>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include <stdarg.h>

pthread_mutex_t mtx;

enum level
{
    DEBUG = 1,
    INFO,
    WARNING,
    ERROR,
    FATAL
};
enum Type
{
    PRINTTOSCREEN,
    PRINTTOFILE
};

// [日志等级][pid][filename][filenumber][time]日志内容(支持可变参数)
struct LogMessage
{
    std::string _level;
    pid_t _pid;
    std::string _filename;
    int _filenumber;
    std::string _time;
    std::string _message_info;
};
std::string LevelToString(int level)
{
    switch (level)
    {
    case 1:
        return "DEBUG";
    case 2:
        return "INFO";
    case 3:
        return "WARNING";
    case 4:
        return "ERROR";
    case 5:
        return "FATAL";
    default:
        return "NONE";
    }
}
std::string GetCurrentTime()
{
    time_t now = time(nullptr);
    struct tm *curr_time = localtime(&now);
    char buffer[128] = {0};
    // 这里得到的年 = 当前的年份 - 1900
    // 月 ：[0, 11]
    sprintf(buffer, "%04d/%02d/%02d %02d:%02d:%02d", curr_time->tm_year + 1900, curr_time->tm_mon + 1, curr_time->tm_mday, curr_time->tm_hour, curr_time->tm_min, curr_time->tm_sec);
    return buffer;
}
// [日志等级][pid][filename][filenumber][time]日志内容(支持可变参数)
void ptS(const LogMessage &lg)
{
    pthread_mutex_lock(&mtx);
    printf("[%s][%d][%s][%d][%s] %s\n", lg._level.c_str(), lg._pid, lg._filename.c_str(), lg._filenumber, lg._time.c_str(), lg._message_info.c_str());
    pthread_mutex_unlock(&mtx);
}
void ptF(const LogMessage &lg)
{
    pthread_mutex_lock(&mtx);
    FILE *fp = fopen("log.txt", "a");

    fprintf(fp, "[%s][%d][%s][%d][%s] %s\n", lg._level.c_str(), lg._pid, lg._filename.c_str(), lg._filenumber, lg._time.c_str(), lg._message_info.c_str());

    fclose(fp);
    pthread_mutex_unlock(&mtx);
}

class Log
{
private:
    int _type = PRINTTOSCREEN;

public:
    Log() {}
    void flushLog(const LogMessage &lg)
    {
        int type = _type;
        switch (type)
        {
        case PRINTTOSCREEN:
            ptS(lg);
            break;
        case PRINTTOFILE:
            ptF(lg);
            break;
        }
    }
    void logMessage(int level, std::string filename, int filenumber, const char *format, ...)
    {
        LogMessage lg;
        lg._level = LevelToString(level);
        lg._pid = getpid();
        lg._filename = filename;
        lg._filenumber = filenumber;
        lg._time = GetCurrentTime();
        char info[1024] = {0};
        va_list ap;
        va_start(ap, format);
        vsnprintf(info, sizeof(info), format, ap);
        lg._message_info = info;

        // 打印信息
        flushLog(lg);
    }
    ~Log() {}
};

// 简便，不用重复定义Log对象
Log lg;
#define LOG(level, Format, ...)                                        \
    do                                                                 \
    {                                                                  \
        lg.logMessage(level, __FILE__, __LINE__, Format, ##__VA_ARGS__); \
    } while (0)
